/**
* Copyright (c) By zengqh.
*
* This program is just for fun or demo, in the hope that it  
* will be useful, you can redistribute it and/or modify freely.
*
* Time: 2013/05/26
* File: enn_gl_gpu_buffer.cpp
* Blog: http://www.cnblogs.com/zengqh/
**/

#include "enn_gl_gpu_buffer.h"
#include "enn_gl_render_context.h"

namespace enn
{

GPUBuffer::GPUBuffer()
: m_handle(0)
, m_data(0)
, size_(0)
, usage_(0)
, use_memory_(false)
, lock_scratch_data_(0)
{

}

GPUBuffer::~GPUBuffer()
{
	destroyBuff();
}

void  GPUBuffer::release()
{
	ENN_DELETE this;
}

bool  GPUBuffer::createBuff( size_t size, GLenum usage, bool use_memory )
{
	if (size == 0)
	{
		size = sizeof(float);
	}

	destroyBuff();

	size_ = size;
	usage_ = usage;
	use_memory_ = use_memory;

	if (use_memory)
	{
		m_data = ENN_MALLOC(size);
	}
	else
	{
		gl.glGenBuffers( 1, &m_handle );

		GLenum target = getTarget();
		gl.glBindBuffer( target, m_handle );

		gl.glBufferData( target, size, 0, usage );
		gl.glBindBuffer( target, 0 );

		checkGLError();
	}

	return true;
}

void  GPUBuffer::destroyBuff()
{
	ENN_SAFE_FREE(m_data);

	if ( m_handle != 0 )
	{
		gl.glDeleteBuffers( 1, &m_handle );
		m_handle = 0;

		checkGLError();
	}
}

void* GPUBuffer::lock( GLenum access )
{
	if ( !use_memory_ )
	{
		ENN_ASSERT(m_handle);

		lock_scratch_data_ = rc_getRenderSys()->reserveScratchBuffer(size_);

		return lock_scratch_data_;
	}
	else
	{
		return m_data;
	}
}

void  GPUBuffer::unlock()
{
	if ( !use_memory_ )
	{
		ENN_ASSERT(m_handle);

		rc_getRenderSys()->freeScratchBuffer(lock_scratch_data_);
		lock_scratch_data_ = 0;
	}
}

void  GPUBuffer::setData( const void* data )
{
	if (!use_memory_)
	{
		GLenum target = getTarget();
		gl.glBindBuffer( target, m_handle );
		gl.glBufferData( target, size_, data, usage_ );
		gl.glBindBuffer( target, 0 );

		checkGLError();
	}
	else
	{
		memcpy(m_data, data, size_);
	}
}

void GPUBuffer::bind()
{
	if (!use_memory_)
	{
		ENN_ASSERT(m_handle);
		GLenum target = getTarget();
		gl.glBindBuffer( target, m_handle );
	}
	else
	{
		GLenum target = getTarget();
		gl.glBindBuffer( target, 0 );
	}
}

void GPUBuffer::unbind()
{
	if (!use_memory_)
	{
		GLenum target = getTarget();
		gl.glBindBuffer( target, 0 );
	}
}

}